package com.cmict.data.bpm.service.task;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.http.HtmlUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.cmict.data.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
import com.cmict.data.bpm.dal.mysql.task.BpmProcessInstanceExtMapper;
import com.cmict.data.bpm.service.externalfile.ExternalFileCreateBO;
import com.cmict.data.bpm.service.externalfile.ExternalFileInfo;
import com.cmict.data.bpm.service.externalfile.ExternalFileService;
import com.cmict.data.framework.common.enums.CommonStatusEnum;
import com.cmict.data.framework.common.exception.ErrorCode;
import com.cmict.data.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.cmict.data.framework.common.pojo.CommonResult;
import com.cmict.data.framework.common.pojo.PageResult;
import com.cmict.data.framework.common.util.date.DateUtils;
import com.cmict.data.framework.common.util.number.NumberUtils;
import com.cmict.data.bpm.FlowableUtils;
import com.cmict.data.bpm.base.constant.FlowableConstant;
import com.cmict.data.bpm.controller.admin.definition.vo.task.TaskCarbonVO;
import com.cmict.data.bpm.controller.admin.definition.vo.task.TaskVariableCreateReqVO;
import com.cmict.data.bpm.controller.admin.definition.vo.task.TaskVariablePageReqVO;
import com.cmict.data.bpm.controller.admin.task.vo.task.*;
import com.cmict.data.bpm.controller.admin.task.vo.task.message.TaskMessageCreateReqVO;
import com.cmict.data.bpm.dal.dataobject.definition.BpmUserGroupDO;
import com.cmict.data.bpm.dal.dataobject.definition.TaskVariableDO;
import com.cmict.data.bpm.dal.dataobject.task.BpmTaskExtDO;
import com.cmict.data.bpm.dal.dataobject.task.TaskCarbonDO;
import com.cmict.data.bpm.dal.mysql.task.BpmTaskExtMapper;
import com.cmict.data.bpm.dal.mysql.task.IFlowableTaskDao;
import com.cmict.data.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
import com.cmict.data.bpm.enums.task.BpmProcessInstanceActionsEnum;
import com.cmict.data.bpm.enums.task.BpmProcessInstanceResultEnum;
import com.cmict.data.bpm.framework.cmd.FlowClaimTaskCmd;
import com.cmict.data.bpm.service.definition.BpmTaskAssignRuleService;
import com.cmict.data.bpm.service.definition.BpmUserGroupService;
import com.cmict.data.bpm.service.definition.IFlowableBpmnModelService;
import com.cmict.data.bpm.service.definition.TaskVariableService;
import com.cmict.data.bpm.service.message.BpmMessageService;
import com.cmict.data.bpm.service.message.UserMessageListService;
import com.cmict.data.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO;
import com.cmict.data.bpm.service.message.dto.TaskCarbonCreateReqDTO;
import com.cmict.data.system.api.dept.DeptApi;
import com.cmict.data.system.api.dept.dto.DeptRespDTO;
import com.cmict.data.system.api.permission.PermissionApi;
import com.cmict.data.system.api.user.AdminUserApi;
import com.cmict.data.system.api.user.dto.AdminUserRespDTO;
import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.constants.BpmnXMLConstants;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.bpmn.model.Process;
import org.flowable.engine.runtime.ActivityInstance;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.identitylink.api.IdentityLinkType;
import org.flowable.idm.api.User;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.cmict.data.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cmict.data.framework.common.util.collection.CollectionUtils.convertSet;
import static com.cmict.data.bpm.base.constant.FlowableConstant.REJECT_IDENTIFY;
import static com.cmict.data.bpm.enums.ErrorCodeConstants.*;
import static com.cmict.data.framework.web.core.util.WebFrameworkUtils.getLoginUserId;

/**
 * @author liutao
 * @date 2022/4/7
 */

@Slf4j
@Service
public class FlowableTaskServiceImpl extends BaseProcessService implements IFlowableTaskService {

    @Autowired
    private IFlowableTaskDao flowableTaskDao;
    @Autowired
    private IFlowableBpmnModelService flowableBpmnModelService;
    @Autowired
    private BpmTaskExtMapper taskExtMapper;
    @Autowired
    private BpmProcessInstanceService processInstanceService;
    @Autowired
    private BpmMessageService bpmMessageService;
    @Autowired
    private UserMessageListService userMessageService;

    @Lazy
    @Resource
    private IFlowableTaskService flowableTaskService;

    @Autowired
    private BpmTaskAssignRuleService bpmTaskRuleService;
    @Autowired
    private BpmUserGroupService userGroupService;

    @Resource
    private BpmProcessInstanceExtMapper processInstanceExtMapper;
    @Autowired
    private DeptApi deptApi;
    @Autowired
    private AdminUserApi adminUserApi;
    @Autowired
    private PermissionApi permissionApi;
    @Autowired
    private TaskVariableService taskVariableService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private ExternalFileService externalFileService;
    @Override
    public boolean checkParallelgatewayNode(String taskId) {
        boolean flag = false;
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        String executionId = task.getExecutionId();
        Execution execution = runtimeService.createExecutionQuery().executionId(executionId).singleResult();
        String pExecutionId = execution.getParentId();
        Execution pExecution = runtimeService.createExecutionQuery().executionId(pExecutionId).singleResult();
        if (pExecution != null) {
            String ppExecutionId = pExecution.getParentId();
            long count = runtimeService.createExecutionQuery().executionId(ppExecutionId).count();
            if (count == 0) {
                flag = true;
            }
        }
        return flag;
    }


    @Override
    public CommonResult<String> backTask(BackTaskVo backTaskVo) {
        Long userId = getLoginUserId();
        backTaskVo.setUserId(String.valueOf(userId));
        backTaskVo.setReason(HtmlUtil.filter(backTaskVo.getReason()));
        CommonResult<String> returnVo = null;
        TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(backTaskVo.getTaskId()).singleResult();
        //1.把当前的节点设置为空
        if (taskEntity != null) {
            stringRedisTemplate.opsForValue().set(taskEntity.getProcessInstanceId(), REJECT_IDENTIFY,
                    2, TimeUnit.MINUTES);
            //2.设置审批人
            taskEntity.setAssignee(backTaskVo.getUserId());
            taskService.saveTask(taskEntity);
            //3.添加驳回意见
            this.addComment(backTaskVo.getTaskId(), backTaskVo.getProcessInstanceId(),
                    BpmProcessInstanceActionsEnum.BH.toString(), backTaskVo.getReason());
            //4.处理提交人节点
            FlowNode distActivity = flowableBpmnModelService.findFlowNodeByActivityId(taskEntity.getProcessDefinitionId(), backTaskVo.getDistFlowElementId());
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(taskEntity.getProcessInstanceId()).singleResult();
            backTaskVo.setProcessInstanceId(processInstance.getProcessInstanceId());
            if (distActivity != null) {
                if (FlowableConstant.FLOW_SUBMITTER_VAR.equals(distActivity.getId())) {
                    runtimeService.setVariable(processInstance.getProcessInstanceId(), FlowableConstant.FLOW_SUBMITTER_VAR, processInstance.getStartUserId());
                }
            }
            //5.删除节点
            this.deleteActivity(backTaskVo.getDistFlowElementId(), taskEntity.getProcessInstanceId());
            List<String> executionIds = new ArrayList<>();
            //6.判断节点是不是子流程内部的节点
            if (flowableBpmnModelService.checkActivitySubprocessByActivityId(taskEntity.getProcessDefinitionId(),
                    backTaskVo.getDistFlowElementId())
                    && flowableBpmnModelService.checkActivitySubprocessByActivityId(taskEntity.getProcessDefinitionId(),
                    taskEntity.getTaskDefinitionKey())) {
                //6.1 子流程内部驳回
                Execution executionTask = runtimeService.createExecutionQuery().executionId(taskEntity.getExecutionId()).singleResult();
                String parentId = executionTask.getParentId();
                List<Execution> executions = runtimeService.createExecutionQuery().parentId(parentId).list();
                executions.forEach(execution -> executionIds.add(execution.getId()));
                this.moveExecutionsToSingleActivityId(executionIds, backTaskVo.getDistFlowElementId());
            } else {
                //6.2 普通驳回
                List<Execution> executions = runtimeService.createExecutionQuery().parentId(taskEntity.getProcessInstanceId()).list();
                executions.forEach(execution -> executionIds.add(execution.getId()));
                this.moveExecutionsToSingleActivityId(executionIds, backTaskVo.getDistFlowElementId());
            }
            // 任务扩展表状态更新
            taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(backTaskVo.getTaskId())
                    .setResult(BpmProcessInstanceResultEnum.BACK.getResult()).setReason(backTaskVo.getReason()));

            // 驳回到起点时更新流程实例状态为已驳回
            if (distActivity.getIncomingFlows().size() == 1) {
                processInstanceService.updateProcessInstanceExtBack(processInstance.getProcessInstanceId(), backTaskVo.getReason());
            }
            // 如果有审批附近，保存9附件
            createExternalFile(backTaskVo.getTaskId(), backTaskVo.getProcessInstanceId(),backTaskVo.getFileList(),backTaskVo.getImageList());
            returnVo = CommonResult.success("驳回成功", "");
        } else {
            ErrorCode error = new ErrorCode(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "不存在任务实例,请确认!");
            returnVo = CommonResult.error(error);
        }
        return returnVo;
    }

    @Override
    public CommonResult<String> batchBackTask(BackTaskDistVo backTaskVo) {
        for (String taskId : backTaskVo.getTaskIdList()) {
            backTaskVo.setTaskId(taskId);
            Long userId = getLoginUserId();
            backTaskVo.setUserId(String.valueOf(userId));
            backTaskVo.setReason(HtmlUtil.filter(backTaskVo.getReason()));
//        List<FlowNodeVo> backNodes = this.getBackNodes(Long.parseLong(backTaskVo.getUserId()), backTaskVo.getTaskId());
            List<FlowNodeVo> backNodes = this.getBackNodes(backTaskVo.getTaskId());
            if(CollectionUtils.isEmpty(backNodes)){
                throw exception(TASK_N0_REBUFFABLE_NODE);
            }
            FlowNodeVo flowNodeVo;
            if (backTaskVo.getPosition().equalsIgnoreCase("start")) {
                //驳回到起点
                flowNodeVo = backNodes.get(0);
            } else {
                //驳回到上一节点
                flowNodeVo = backNodes.get(backNodes.size() - 1);
            }
            BackTaskVo doBackTaskVo = new BackTaskVo();
            BeanUtils.copyProperties(backTaskVo, doBackTaskVo);
            doBackTaskVo.setDistFlowElementId(flowNodeVo.getNodeId());
            this.backTask(doBackTaskVo);
        }

        return null;
    }

    public void createExternalFile(String taskId, String processInstanceId,
                                   List<ExternalFileInfo> fileList, List<ExternalFileInfo> imageList) {
        ExternalFileCreateBO externalFileCreateBO = new ExternalFileCreateBO().setTaskId(taskId)
                .setProcessInstanceId(processInstanceId).setFileList(fileList).setImageList(imageList);
        externalFileService.createExternalFile(externalFileCreateBO);
    }
    @Override
    public CommonResult<String> backTask(BackTaskDistVo backTaskVo) {
        Long userId = getLoginUserId();
        backTaskVo.setUserId(String.valueOf(userId));
        backTaskVo.setReason(HtmlUtil.filter(backTaskVo.getReason()));
//        List<FlowNodeVo> backNodes = this.getBackNodes(Long.parseLong(backTaskVo.getUserId()), backTaskVo.getTaskId());
        List<FlowNodeVo> backNodes = this.getBackNodes(backTaskVo.getTaskId());
        if(CollectionUtils.isEmpty(backNodes)){
            throw exception(TASK_N0_REBUFFABLE_NODE);
        }
        FlowNodeVo flowNodeVo;
        if (backTaskVo.getPosition().equalsIgnoreCase("start")) {
            //驳回到起点
            flowNodeVo = backNodes.get(0);
        } else {
            //驳回到上一节点
            flowNodeVo = backNodes.get(backNodes.size() - 1);
        }
        BackTaskVo doBackTaskVo = new BackTaskVo();
        BeanUtils.copyProperties(backTaskVo, doBackTaskVo);
        doBackTaskVo.setDistFlowElementId(flowNodeVo.getNodeId());
        return this.backTask(doBackTaskVo);
    }

    /**
     * 校验任务是否存在， 并且是否是分配给自己的任务
     *
     * @param userId 用户 id
     * @param taskId task id
     */
    private Task checkTask(Long userId, String taskId) {
        Task task = getTask(taskId);
        if (task == null) {
            throw exception(TASK_COMPLETE_FAIL_NOT_EXISTS);
        }
        if (!Objects.equals(userId, NumberUtils.parseLong(task.getAssignee()))) {
            throw exception(TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF);
        }
        return task;
    }

    private Task getTask(String id) {
        return taskService.createTaskQuery().taskId(id).singleResult();
    }

    @Override
    public List<FlowNodeVo> getBackNodes(Long userId, String taskId) {
        TaskEntity taskEntity = (TaskEntity) checkTask(userId, taskId);
        String processInstanceId = taskEntity.getProcessInstanceId();
        String currActId = taskEntity.getTaskDefinitionKey();
        String processDefinitionId = taskEntity.getProcessDefinitionId();
        Process process = repositoryService.getBpmnModel(processDefinitionId).getMainProcess();
        FlowNode currentFlowElement = (FlowNode) process.getFlowElement(currActId, true);
        List<ActivityInstance> activities = runtimeService.createActivityInstanceQuery()
                .processInstanceId(processInstanceId).finished()
                .orderByActivityInstanceStartTime().asc().list();
        List<String> activityIds = activities.stream()
                .filter(activity -> activity.getActivityType().equals(BpmnXMLConstants.ELEMENT_TASK_USER))
                .filter(activity -> !activity.getActivityId().equals(currActId))
                .map(ActivityInstance::getActivityId).distinct().collect(Collectors.toList());
        List<FlowNodeVo> result = new ArrayList<>();
        for (String activityId : activityIds) {
            FlowNode toBackFlowElement = (FlowNode) process.getFlowElement(activityId, true);
            if (FlowableUtils.isReachable(process, toBackFlowElement, currentFlowElement)) {
                FlowNodeVo vo = new FlowNodeVo();
                vo.setNodeId(activityId);
                vo.setNodeName(toBackFlowElement.getName());
                result.add(vo);
            }
        }
        return result;
    }

    @Override
    public List<FlowNodeVo> getBackNodes(String taskId) {
        List<FlowNodeVo> backNods = new ArrayList<>();
        TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(taskId).singleResult();
        String processInstanceId = taskEntity.getProcessInstanceId();
        String currActId = taskEntity.getTaskDefinitionKey();
        //获取运行节点表中usertask
        String sql = "select t.* from act_ru_actinst t where t.ACT_TYPE_ = 'userTask' " +
                " and t.PROC_INST_ID_=#{processInstanceId} and t.END_TIME_ is not null ";
        List<ActivityInstance> activityInstances = runtimeService.createNativeActivityInstanceQuery().sql(sql)
                .parameter("processInstanceId", processInstanceId)
                .list();
        //获取运行节点表的parallelGateway节点并去重
        sql = "SELECT t.ID_, t.REV_,t.PROC_DEF_ID_,t.PROC_INST_ID_,t.EXECUTION_ID_,t.ACT_ID_, t.TASK_ID_, t.CALL_PROC_INST_ID_, t.ACT_NAME_, t.ACT_TYPE_, " +
                " t.ASSIGNEE_, t.START_TIME_, max(t.END_TIME_) as END_TIME_, t.DURATION_, t.DELETE_REASON_, t.TENANT_ID_" +
                " FROM  act_ru_actinst t WHERE t.ACT_TYPE_ = 'parallelGateway' AND t.PROC_INST_ID_ = #{processInstanceId} and t.END_TIME_ is not null" +
                " and t.ACT_ID_ <> #{actId} GROUP BY t.ID_, t.act_id_,t.REV_,t.PROC_DEF_ID_,t.PROC_INST_ID_,t.EXECUTION_ID_,t.ACT_ID_, t.TASK_ID_, t.CALL_PROC_INST_ID_, t.ACT_NAME_, t.ACT_TYPE_, " +
                " t.ASSIGNEE_, t.START_TIME_,t.DURATION_, t.DELETE_REASON_, t.TENANT_ID_";
        List<ActivityInstance> parallelGatewaies = runtimeService.createNativeActivityInstanceQuery().sql(sql)
                .parameter("processInstanceId", processInstanceId)
                .parameter("actId", currActId)
                .list();
        //排序
        if (CollectionUtils.isNotEmpty(parallelGatewaies)) {
            activityInstances.addAll(parallelGatewaies);
            activityInstances.sort(Comparator.comparing(ActivityInstance::getEndTime));
        }
        //分组节点
        int count = 0;
        Map<ActivityInstance, List<ActivityInstance>> parallelGatewayUserTasks = new HashMap<>();
        List<ActivityInstance> userTasks = new ArrayList<>();
        ActivityInstance currActivityInstance = null;
        for (ActivityInstance activityInstance : activityInstances) {
            if (BpmnXMLConstants.ELEMENT_GATEWAY_PARALLEL.equals(activityInstance.getActivityType())) {
                count++;
                if (count % 2 != 0) {
                    List<ActivityInstance> datas = new ArrayList<>();
                    currActivityInstance = activityInstance;
                    parallelGatewayUserTasks.put(currActivityInstance, datas);
                }
            }
            if (BpmnXMLConstants.ELEMENT_TASK_USER.equals(activityInstance.getActivityType())) {
                if (count % 2 == 0) {
                    userTasks.add(activityInstance);
                } else {
                    if (parallelGatewayUserTasks.containsKey(currActivityInstance)) {
                        parallelGatewayUserTasks.get(currActivityInstance).add(activityInstance);
                    }
                }
            }
        }
        //组装人员名称
        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId).finished().list();
        Map<String, List<HistoricTaskInstance>> taskInstanceMap = new HashMap<>();
        List<String> userCodes = new ArrayList<>();
        historicTaskInstances.forEach(historicTaskInstance -> {
            userCodes.add(historicTaskInstance.getAssignee());
            String taskDefinitionKey = historicTaskInstance.getTaskDefinitionKey();
            if (taskInstanceMap.containsKey(historicTaskInstance.getTaskDefinitionKey())) {
                taskInstanceMap.get(taskDefinitionKey).add(historicTaskInstance);
            } else {
                List<HistoricTaskInstance> tasks = new ArrayList<>();
                tasks.add(historicTaskInstance);
                taskInstanceMap.put(taskDefinitionKey, tasks);
            }
        });
        //组装userTask的数据
        List<User> userList = identityService.createUserQuery().userIds(userCodes).list();
        Map<String, String> activityIdUserNames = this.getApplyers(processInstanceId, userList, taskInstanceMap);
        if (CollectionUtils.isNotEmpty(userTasks)) {
            userTasks.forEach(activityInstance -> {
                FlowNodeVo node = new FlowNodeVo();
                node.setNodeId(activityInstance.getActivityId());
                node.setNodeName(activityInstance.getActivityName());
                node.setEndTime(DateUtils.of(activityInstance.getEndTime()));
                node.setUserName(activityIdUserNames.get(activityInstance.getActivityId()));
                backNods.add(node);
            });
        }
        //组装会签节点数据
        if (taskInstanceMap != null && !taskInstanceMap.isEmpty()) {
            parallelGatewayUserTasks.forEach((activity, activities) -> {
                FlowNodeVo node = new FlowNodeVo();
                node.setNodeId(activity.getActivityId());
                node.setEndTime(DateUtils.of(activity.getEndTime()));
                StringBuffer nodeNames = new StringBuffer("会签:");
                StringBuffer userNames = new StringBuffer("审批人员:");
                if (CollectionUtils.isNotEmpty(activities)) {
                    activities.forEach(activityInstance -> {
                        nodeNames.append(activityInstance.getActivityName()).append(",");
                        userNames.append(activityIdUserNames.get(activityInstance.getActivityId())).append(",");
                    });
                    node.setNodeName(nodeNames.toString());
                    node.setUserName(userNames.toString());
                    backNods.add(node);
                }
            });
        }
        //去重合并
        List<FlowNodeVo> datas = backNods.stream().collect(
                Collectors.collectingAndThen(Collectors.toCollection(() ->
                        new TreeSet<>(Comparator.comparing(nodeVo -> nodeVo.getNodeId()))), ArrayList::new));

        //排序
        datas.sort(Comparator.comparing(FlowNodeVo::getEndTime));
        return datas;
    }

    private Map<String, String> getApplyers(String processInstanceId, List<User> userList, Map<String, List<HistoricTaskInstance>> taskInstanceMap) {
        Map<String, User> userMap = userList.stream().collect(Collectors.toMap(User::getId, user -> user));
        Map<String, String> applyMap = new HashMap<>();
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        taskInstanceMap.forEach((activityId, taskInstances) -> {
            StringBuffer applyers = new StringBuffer();
            StringBuffer finalApplyers = applyers;
            taskInstances.forEach(taskInstance -> {
                // askInstance.getName().equals(FlowableConstant.FLOW_SUBMITTER) 是如何设置的，为何相等
                if (StringUtils.isBlank(taskInstance.getName()) || !taskInstance.getName().equals(FlowableConstant.FLOW_SUBMITTER)) {
                    User user = userMap.get(taskInstance.getAssignee());
                    if (user != null) {
                        if (StringUtils.indexOf(finalApplyers.toString(), user.getDisplayName()) == -1) {
                            finalApplyers.append(user.getDisplayName()).append(",");
                        }
                    }
                } else {
                    String startUserId = processInstance.getStartUserId();
                    User user = identityService.createUserQuery().userId(startUserId).singleResult();
                    if (user != null) {
                        finalApplyers.append(user.getDisplayName()).append(",");
                    }
                }
            });
            if (applyers.length() > 0) {
                applyers = applyers.deleteCharAt(applyers.length() - 1);
            }
            applyMap.put(activityId, applyers.toString());
        });
        return applyMap;
    }

    @Override
    public CommonResult<String> beforeAddSignTask(AddSignTaskVo addSignTaskVo) {
        return this.addSignTask(addSignTaskVo, false);
    }

    @Override
    public CommonResult<String> afterAddSignTask(AddSignTaskVo addSignTaskVo) {
        return this.addSignTask(addSignTaskVo, true);
    }

    @Override
    public CommonResult<String> addSignTask(AddSignTaskVo addSignTaskVo, Boolean flag) {
        CommonResult<String> returnVo = null;
        TaskEntityImpl taskEntity = (TaskEntityImpl) taskService.createTaskQuery().taskId(addSignTaskVo.getTaskId()).singleResult();
        //1.把当前的节点设置为空
        if (taskEntity != null) {
            //如果是加签再加签
            String parentTaskId = taskEntity.getParentTaskId();
            if (StringUtils.isBlank(parentTaskId)) {
                taskEntity.setOwner(addSignTaskVo.getUserId());
                taskEntity.setAssignee(null);
                taskEntity.setCountEnabled(true);
                if (flag) {
                    taskEntity.setScopeType(FlowableConstant.AFTER_ADDSIGN);
                } else {
                    taskEntity.setScopeType(FlowableConstant.BEFORE_ADDSIGN);
                }
                //1.2 设置任务为空执行者
                taskService.saveTask(taskEntity);
            }
            //2.添加加签数据
            this.createSignSubTasks(addSignTaskVo, taskEntity);
            //3.添加审批意见
            String type = flag ? BpmProcessInstanceActionsEnum.HJQ.toString() : BpmProcessInstanceActionsEnum.QJQ.toString();
            this.addComment(addSignTaskVo.getTaskId(), addSignTaskVo.getProcessInstanceId(),
                    type, addSignTaskVo.getReason());
            String message = flag ? "后加签成功" : "前加签成功";
            returnVo = CommonResult.success(message, "");
        } else {
            ErrorCode error = new ErrorCode(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "不存在任务实例,请确认!");
            returnVo = CommonResult.error(error);
        }
        return returnVo;
    }

    /**
     * 创建加签子任务
     *
     * @param signVo     加签参数
     * @param taskEntity 父任务
     */
    private void createSignSubTasks(AddSignTaskVo signVo, TaskEntity taskEntity) {
        if (CollectionUtils.isNotEmpty(signVo.getSignPersoneds())) {
            String parentTaskId = taskEntity.getParentTaskId();
            if (StringUtils.isBlank(parentTaskId)) {
                parentTaskId = taskEntity.getId();
            }
            String finalParentTaskId = parentTaskId;
            //1.创建被加签人的任务列表
            signVo.getSignPersoneds().forEach(userCode -> {
                if (StringUtils.isNotBlank(userCode)) {
                    this.createSubTask(taskEntity, finalParentTaskId, userCode);
                }
            });
            String taskId = taskEntity.getId();
            if (StringUtils.isBlank(taskEntity.getParentTaskId())) {
                //2.创建加签人的任务并执行完毕
                Task task = this.createSubTask(taskEntity, finalParentTaskId, signVo.getUserId());
                taskId = task.getId();
            }
            Task taskInfo = taskService.createTaskQuery().taskId(taskId).singleResult();
            if (null != taskInfo) {
                taskService.complete(taskId);
            }
            //如果是候选人，需要删除运行时候选表种的数据。
            long candidateCount = taskService.createTaskQuery().taskId(parentTaskId).taskCandidateUser(signVo.getUserId()).count();
            if (candidateCount > 0) {
                taskService.deleteCandidateUser(parentTaskId, signVo.getUserId());
            }
        }
    }

    @Override
    public CommonResult<String> unClaimTask(ClaimTaskVo claimTaskVo) {
        CommonResult<String> returnVo = null;
        TaskEntityImpl currTask = (TaskEntityImpl) taskService.createTaskQuery().taskId(claimTaskVo.getTaskId()).singleResult();
        if (currTask != null) {
            //1.添加审批意见
            this.addComment(claimTaskVo.getTaskId(), claimTaskVo.getUserId(), claimTaskVo.getProcessInstanceId(), BpmProcessInstanceActionsEnum.QS.toString(), claimTaskVo.getReason());
            List<IdentityLink> identityLinks = taskService.getIdentityLinksForTask(claimTaskVo.getTaskId());
            boolean flag = false;
            if (CollectionUtils.isNotEmpty(identityLinks)) {
                for (IdentityLink link : identityLinks) {
                    if (IdentityLinkType.CANDIDATE.equals(link.getType())) {
                        flag = true;
                        break;
                    }
                }
            }
            //2.反签收
            if (flag) {
//                taskService.claim(claimTaskVo.getTaskId(), null);
                managementService.executeCommand(new FlowClaimTaskCmd(claimTaskVo.getTaskId(), null));
                returnVo = CommonResult.success("反签收成功", "");
            } else {
                ErrorCode error = new ErrorCode(GlobalErrorCodeConstants.UNKNOWN.getCode(), "由于没有候选人或候选组,会导致任务无法认领,请确认.");
                returnVo = CommonResult.error(error);
            }
        } else {
            ErrorCode error = new ErrorCode(GlobalErrorCodeConstants.UNKNOWN.getCode(), "反签收失败");
            returnVo = CommonResult.error(error);

        }
        return returnVo;
    }

    @Override
    public CommonResult<String> claimTask(ClaimTaskVo claimTaskVo) {
        CommonResult<String> returnVo = null;
        TaskEntityImpl currTask = (TaskEntityImpl) taskService.createTaskQuery().taskId(claimTaskVo.getTaskId()).singleResult();
        if (currTask != null) {
            //1.添加审批意见
            this.addComment(claimTaskVo.getTaskId(), claimTaskVo.getProcessInstanceId(), BpmProcessInstanceActionsEnum.QS.toString(), claimTaskVo.getReason());
            //2.签收
            managementService.executeCommand(new FlowClaimTaskCmd(claimTaskVo.getTaskId(), claimTaskVo.getUserId()));
//            taskService.claim(claimTaskVo.getTaskId(), claimTaskVo.getUserCode());
            returnVo = CommonResult.success("签收成功", "");
        } else {
            ErrorCode error = new ErrorCode(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "签收失败");
            returnVo = CommonResult.error(error);
        }
        return returnVo;
    }

    @Override
    public CommonResult<String> delegateTask(DelegateTaskVo delegateTaskVo) {
        CommonResult<String> returnVo = null;
        TaskEntityImpl currTask = (TaskEntityImpl) taskService.createTaskQuery().taskId(delegateTaskVo.getTaskId()).singleResult();
        if (currTask != null) {
            //1.添加审批意见
            this.addComment(delegateTaskVo.getTaskId(), delegateTaskVo.getProcessInstanceId(), BpmProcessInstanceActionsEnum.WP.toString(), delegateTaskVo.getReason());
            //2.设置审批人就是当前登录人
            taskService.setAssignee(delegateTaskVo.getTaskId(), delegateTaskVo.getUserId());
            //3.执行委派
            taskService.delegateTask(delegateTaskVo.getTaskId(), delegateTaskVo.getDelegateUserCode());
            returnVo = CommonResult.success("委派成功", "");
        } else {
            ErrorCode error = new ErrorCode(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "没有运行时的任务实例,请确认!");
            returnVo = CommonResult.error(error);
        }
        return returnVo;
    }

    @Override
    public CommonResult<String> turnTask(TurnTaskVo turnTaskVo) {
        CommonResult<String> returnVo = null;
        TaskEntityImpl currTask = (TaskEntityImpl) taskService.createTaskQuery().taskId(turnTaskVo.getTaskId()).singleResult();
        if (currTask != null) {
            //1.生成历史记录
            TaskEntity task = this.createSubTask(currTask, turnTaskVo.getUserId());
            //2.添加审批意见
            this.addComment(task.getId(), turnTaskVo.getProcessInstanceId(), BpmProcessInstanceActionsEnum.ZB.toString(), turnTaskVo.getReason());
            taskService.complete(task.getId());
            //3.转办
            taskService.setAssignee(turnTaskVo.getTaskId(), turnTaskVo.getTurnToUserId());
            taskService.setOwner(turnTaskVo.getTaskId(), turnTaskVo.getUserId());
            returnVo = CommonResult.success("转办成功", "");
        } else {
            ErrorCode error = new ErrorCode(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "没有运行时的任务实例,请确认!");
            returnVo = CommonResult.error(error);
        }
        return returnVo;
    }

    @Override
    public CommonResult<String> complete(CompleteTaskVo params) {
        CommonResult<String> returnVo = returnVo = CommonResult.success("审批成功", "");
        if (StringUtils.isNotBlank(params.getProcessInstanceId())
                && StringUtils.isNotBlank(params.getTaskId())) {
            //1.查看当前任务是存在
            TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(params.getTaskId()).singleResult();
            if (taskEntity != null) {
                String taskId = params.getTaskId();
                //2.委派处理
                if (DelegationState.PENDING.equals(taskEntity.getDelegationState())) {
                    //2.1生成历史记录
                    TaskEntity task = this.createSubTask(taskEntity, params.getUserId());
                    taskService.complete(task.getId());
                    taskId = task.getId();
                    //2.2执行委派
                    taskService.resolveTask(params.getTaskId(), params.getVariables());
                } else {
                    //3.1修改执行人 其实我这里就相当于签收了
                    taskService.setAssignee(params.getTaskId(), params.getUserId());
                    //3.2执行任务
                    taskService.complete(params.getTaskId(), params.getVariables());
                    //4.处理加签父任务
                    String parentTaskId = taskEntity.getParentTaskId();
                    if (StringUtils.isNotBlank(parentTaskId)) {
                        String tableName = managementService.getTableName(TaskEntity.class);
                        String sql = "select count(1) from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}";
                        long subTaskCount = taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).count();
                        if (subTaskCount == 0) {
                            Task task = taskService.createTaskQuery().taskId(parentTaskId).singleResult();
                            //处理前后加签的任务
                            taskService.resolveTask(parentTaskId);
                            if (FlowableConstant.AFTER_ADDSIGN.equals(task.getScopeType())) {
                                taskService.complete(parentTaskId);
                            }
                        }
                    }
                }
                String type = params.getType() == null ? BpmProcessInstanceActionsEnum.SP.toString() : params.getType();
                //5.生成审批意见
                this.addComment(taskId, params.getProcessInstanceId(), type, params.getReason());
            } else {
                ErrorCode error = new ErrorCode(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "没有此任务，请确认!");
                returnVo = CommonResult.error(error);
            }
        } else {
            ErrorCode error = new ErrorCode(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "请输入正确的参数!");
            returnVo = CommonResult.error(error);
        }
        return returnVo;
    }

    @Override
    public CommonResult<Task> findTaskById(String taskId) {
        CommonResult<Task> returnVo = CommonResult.success("转办成功", null);
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        returnVo.setData(task);
        return returnVo;
    }

//    @Override
//    public Page<TaskVo> getApplyingTasks(TaskQueryVo params, Query query) {
//        PageHelper.startPage(query.getPageNum(), query.getPageSize());
//        Page<TaskVo> applyingTasks = flowableTaskDao.getApplyingTasks(params);
//        return applyingTasks;
//    }
//
//    @Override
//    public Page<TaskVo> getApplyedTasks(TaskQueryVo params, Query query) {
//        PageHelper.startPage(query.getPageNum(), query.getPageSize());
//        Page<TaskVo> applyedTasks = flowableTaskDao.getApplyedTasks(params);
//        return applyedTasks;
//    }

    @Override
    public List<User> getApprovers(String processInstanceId) {
        List<User> users = new ArrayList<>();
        List<Task> list = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        if (CollectionUtils.isNotEmpty(list)) {
            list.forEach(task -> {
                if (StringUtils.isNotBlank(task.getAssignee())) {
                    //1.审批人ASSIGNEE_是用户id
                    User user = identityService.createUserQuery().userId(task.getAssignee()).singleResult();
                    if (user != null) {
                        users.add(user);
                    }
                    //2.审批人ASSIGNEE_是组id
                    List<User> gusers = identityService.createUserQuery().memberOfGroup(task.getAssignee()).list();
                    if (CollectionUtils.isNotEmpty(gusers)) {
                        users.addAll(gusers);
                    }
                } else {
                    List<IdentityLink> identityLinks = taskService.getIdentityLinksForTask(task.getId());
                    if (CollectionUtils.isNotEmpty(identityLinks)) {
                        identityLinks.forEach(identityLink -> {
                            //3.审批人ASSIGNEE_为空,用户id
                            if (StringUtils.isNotBlank(identityLink.getUserId())) {
                                User user = identityService.createUserQuery().userId(identityLink.getUserId()).singleResult();
                                if (user != null) {
                                    users.add(user);
                                }
                            } else {
                                //4.审批人ASSIGNEE_为空,组id
                                List<User> gusers = identityService.createUserQuery().memberOfGroup(identityLink.getGroupId()).list();
                                if (CollectionUtils.isNotEmpty(gusers)) {
                                    users.addAll(gusers);
                                }
                            }
                        });
                    }
                }
            });
        }
        return users;
    }

    @Override
    public boolean createCarbonTask(CarbonTaskInfoVo taskInfoVo) {
        TaskVariableDO taskVariable = taskVariableService.selectOne(taskInfoVo);
        if(taskVariable == null){
            return false;
        }

        ProcessInstance processInstance = processInstanceService.getProcessInstance(taskInfoVo.getProcessInstanceId());
        String options = taskVariable.getOptions();
        if (taskVariable != null && StringUtils.isNoneBlank(options)) {
            String[] userIds = options.split(",");
            for (String userId : userIds) {
                BpmMessageSendWhenTaskCreatedReqDTO reqDTO = new BpmMessageSendWhenTaskCreatedReqDTO();
                BeanUtils.copyProperties(processInstance, reqDTO);
                reqDTO.setStartUserId(Long.parseLong(processInstance.getStartUserId()));
                reqDTO.setProcessInstanceName(processInstance.getProcessDefinitionName());
                reqDTO.setChannel(Arrays.asList(Integer.valueOf(1)));
                reqDTO.setAssigneeUserId(Long.parseLong(userId));
                userMessageService.sendMessageWhenTaskCarbon(reqDTO);
                //设置抄送任务
                TaskCarbonCreateReqDTO taskCarbonCreateReqDTO = new TaskCarbonCreateReqDTO();
                BeanUtils.copyProperties(reqDTO, taskCarbonCreateReqDTO);
                taskCarbonCreateReqDTO.setUserId(Long.parseLong(userId));
                taskCarbonCreateReqDTO.setStartUserId(Long.parseLong(processInstance.getStartUserId()));
                taskCarbonCreateReqDTO.setTaskId(taskVariable.getTaskId());
                taskCarbonCreateReqDTO.setTaskName(taskInfoVo.getTaskName());
                taskCarbonCreateReqDTO.setProcessInstanceName(processInstance.getName());
                taskCarbonCreateReqDTO.setProcessDefinitionName(processInstance.getProcessDefinitionName());
                userMessageService.createUserMessageList(taskCarbonCreateReqDTO);
            }
            return true;
        }
        return false;
    }

    @Override
    public Long createCarbonVariable(TaskVariableCreateReqVO taskVariableCreateReqVO) {
//        taskVariableService.deleteTaskVariableWithTaskId(taskVariableCreateReqVO.getTaskId());
        List<String> userIds = taskVariableCreateReqVO.getUserIds();
        String users = String.join(",", userIds);
        taskVariableCreateReqVO.setOptions(users);
        taskVariableCreateReqVO.setName("carbon");
        taskVariableCreateReqVO.setType("CARBON");
        Long variableId = taskVariableService.createTaskVariable(taskVariableCreateReqVO);
        CarbonTaskInfoVo taskInfoVo = new CarbonTaskInfoVo();
        taskInfoVo.setTaskId(taskVariableCreateReqVO.getTaskId());
        taskInfoVo.setTaskName(taskVariableCreateReqVO.getName());
        taskInfoVo.setProcessInstanceId(taskVariableCreateReqVO.getProcessInstanceId());
        flowableTaskService.createCarbonTask(taskInfoVo);
        return variableId;
    }

    @Override
    public Long createBatchCarbonVariable(TaskVariableCreateReqVO taskVariableCreateReqVO) {
        List<String> processInstanceIdList = taskVariableCreateReqVO.getProcessInstanceIdList();
        for (int i = 0; i < processInstanceIdList.size(); i++) {
            taskVariableCreateReqVO.setTaskId(processInstanceIdList.get(i));
            taskVariableCreateReqVO.setProcessInstanceId(taskVariableCreateReqVO.getProcessInstanceIdList().get(i));
            //        taskVariableService.deleteTaskVariableWithTaskId(taskVariableCreateReqVO.getTaskId());
            List<String> userIds = taskVariableCreateReqVO.getUserIds();
            String users = String.join(",", userIds);
            taskVariableCreateReqVO.setOptions(users);
            taskVariableCreateReqVO.setName("carbon");
            taskVariableCreateReqVO.setType("CARBON");
            Long variableId = taskVariableService.createTaskVariable(taskVariableCreateReqVO);
        }
        return null;

    }

    @Override
    public PageResult<TaskCarbonVO> getCarbonTask(TaskVariablePageReqVO pageReqVO) {
        PageResult<TaskCarbonDO> taskCarbonPages = userMessageService.selectPage(pageReqVO);
        List<TaskCarbonDO> taskCarbonDOS = taskCarbonPages.getList();
        List<TaskCarbonVO> taskCarbonVOS = new ArrayList<>();
        for (TaskCarbonDO taskCarbonDO : taskCarbonDOS) {
            TaskCarbonVO taskCarbonVO = new TaskCarbonVO();
            BeanUtils.copyProperties(taskCarbonDO, taskCarbonVO);
            String taskId = taskCarbonDO.getTaskId();
            List<BpmTaskExtDO> bpmTaskExtDOS = taskExtMapper.selectListByTaskIds(Arrays.asList(taskId));
            String reason = bpmTaskExtDOS.isEmpty() ? "未设置审批原因" : bpmTaskExtDOS.get(0).getReason();
            taskCarbonVO.setReason(reason);
            BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(taskCarbonDO.getProcessInstanceId());
            Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", taskCarbonDO.getProcessInstanceId());
            taskCarbonVO.setFormRecordId(processInstanceExt.getFormRecordId());
            Long startUserId = taskCarbonDO.getStartUserId();
            AdminUserRespDTO user = adminUserApi.getUser(startUserId).getCheckedData();
            taskCarbonVO.setStartUser(user.getNickname());
            taskCarbonVOS.add(taskCarbonVO);
        }
        return new PageResult<>(taskCarbonVOS, Long.valueOf(taskCarbonVOS.size()));
    }

    @Override
    public boolean completeCarbonTask(Long carbonId) {
        return userMessageService.completeTask(carbonId);
    }

    @Override
    public boolean deleteCarbonTask(Long carbonId) {
        int i = userMessageService.deleteCarbonTask(carbonId);
        return i > 0;
    }

    @Override
    public void batchDeleteCarbon(Collection<Long> ids) {
        userMessageService.batchDeleteCarbon(ids);
    }

    Set<Long> calculateTaskCandidateUsers(TaskMessageCreateReqVO rule) {
        Integer ruleType = rule.getRuleType();
        String options = rule.getOptions();
        List<Long> ruleIdList = JSON.parseArray(options, Long.class);
        Set<Long> assigneeUserIds = null;
        if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), ruleType)) {
            assigneeUserIds = calculateTaskCandidateUsersByRole(ruleIdList);
        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), ruleType)) {
            assigneeUserIds = calculateTaskCandidateUsersByDeptMember(ruleIdList);
        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), ruleType)) {
            assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(ruleIdList);
        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), ruleType)) {
            assigneeUserIds = calculateTaskCandidateUsersByPost(ruleIdList);
        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), ruleType)) {
            assigneeUserIds = calculateTaskCandidateUsersByUser(ruleIdList);
        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), ruleType)) {
            assigneeUserIds = calculateTaskCandidateUsersByUserGroup(ruleIdList);
        }
        // 移除被禁用的用户
        removeDisableUsers(assigneeUserIds);
        if (CollUtil.isEmpty(assigneeUserIds)) {
            throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER);
        }
        return assigneeUserIds;
    }

    private Set<Long> calculateTaskCandidateUsersByRole(List<Long> ruleIdList) {
        CommonResult<Set<Long>> result = permissionApi.getUserRoleIdListByRoleIds(ruleIdList);
        return result.getCheckedData();
    }

    private Set<Long> calculateTaskCandidateUsersByDeptMember(List<Long> ruleIdList) {
        List<AdminUserRespDTO> users = adminUserApi.getUserMapByDeptIds(ruleIdList).values().stream().collect(Collectors.toList());
        return convertSet(users, AdminUserRespDTO::getId);
    }

    private Set<Long> calculateTaskCandidateUsersByDeptLeader(List<Long> ruleIdList) {
        List<DeptRespDTO> depts = deptApi.getDeptMapByListIds(ruleIdList).values().stream().collect(Collectors.toList());
        return convertSet(depts, DeptRespDTO::getLeaderUserId);
    }

    private Set<Long> calculateTaskCandidateUsersByPost(List<Long> ruleIdList) {
        List<AdminUserRespDTO> users = adminUserApi.getUserMapByPostIds(ruleIdList).values().stream().collect(Collectors.toList());
        return convertSet(users, AdminUserRespDTO::getId);
    }

    private Set<Long> calculateTaskCandidateUsersByUser(List<Long> ruleIdList) {
        return new HashSet<>(ruleIdList);
    }

    private Set<Long> calculateTaskCandidateUsersByUserGroup(List<Long> ruleIdList) {
        List<BpmUserGroupDO> userGroups = userGroupService.getUserGroupList(ruleIdList);
        Set<Long> userIds = new HashSet<>();
        userGroups.forEach(group -> userIds.addAll(group.getMemberUserIds()));
        return userIds;
    }

    @VisibleForTesting
    void removeDisableUsers(Set<Long> assigneeUserIds) {
        if (CollUtil.isEmpty(assigneeUserIds)) {
            return;
        }
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assigneeUserIds);
        assigneeUserIds.removeIf(id -> {
            AdminUserRespDTO user = userMap.get(id);
            return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus());
        });
    }
}
